var NOT_MOVING = 0;
var MOVING_DRIVE = 1; // forward and backward
var MOVING_TURN = 2; // turning left and right

var interface_language = 'fi';

var rover = {
    moving: NOT_MOVING,
    speed: 0,
    camh: 90,
    camv: 90,
    control_camera: false,
    stop: function() {
        if (this.moving != NOT_MOVING) {
            this.moving = NOT_MOVING;
            this.speed = 0;
            mars.send('send:s');
        }
    },
    setSpeed: function(newspeed) {
        if (newspeed != this.speed) {
            this.speed = newspeed;
            if (newspeed == 0)
                mars.send('send:s');
            else if (this.moving == MOVING_DRIVE && newspeed > 0)
                mars.send('send:e'+newspeed);
            else if (this.moving == MOVING_DRIVE && newspeed < 0)
                mars.send('send:t'+(-newspeed));
            else if (this.moving == MOVING_TURN && newspeed > 0)
                mars.send('send:o'+newspeed);
            else if (this.moving == MOVING_TURN && newspeed < 0)
                mars.send('send:v'+(-newspeed));
        }
    },
    setCameraH: function(angle) {
        if (angle != this.camh) {
            this.camh = angle;
            mars.send('send:h'+angle);
        }
    },
    setCameraV: function(angle) {
        if (angle != this.camv) {
            this.camv = angle;
            mars.send('send:p'+angle);
        }
    },
    askCameraPosition: function() {
        mars.send('send:!');
    },
    attachCamera: function(setmode) {
        if (setmode !== false)
            this.camera = true;
        mars.send('send:k');
    },
    detachCamera: function() {
        this.camera = false;
        mars.send('send:K');
    },
};
var mars = {send: function(){}}; // this will become the connection

function create_pad() {
    var min_movement = 0.2; // need to move the knob at least 20%
    var min_turning = 0.45;  // will start turning only at 0.5
    
    var stage = new Kinetic.Stage({
        container: 'control_pad',
        width: 330,
        height: 330
    });
    
    var shapesLayer = new Kinetic.Layer();
    /*
    var text_x = new Kinetic.Text({
        x: 10,
        y: 10,
        text: 'x',
        fontSize: 10,
        fontFamily: 'Calibri',
        textFill: 'black'
    });
    
    var text_y = new Kinetic.Text({
        x: 10,
        y: 30,
        text: 'y',
        fontSize: 10,
        fontFamily: 'Calibri',
        textFill: 'black'
    });
    */
    
    var start_x = stage.getWidth() / 2;
    var start_y = stage.getHeight() / 2;
    var max_turning = stage.getWidth() / 3.0 - 5;
    var max_driving = stage.getHeight() / 3.0 - 5;
    var max_camera = (max_turning + max_driving) / 2;
    
    var horz_line = new Kinetic.Line({
        points: [start_x-max_turning, start_y, start_x+max_turning, start_y],
        stroke: "green",
        strokeWidth: 5,
        lineJoin: "round",
        dashArray: [5, 5]
    });
    
    var vert_line = new Kinetic.Line({
        points: [start_x, start_y-max_driving, start_x, start_y+max_driving],
        stroke: "green",
        strokeWidth: 5,
        lineJoin: "round",
        dashArray: [5, 5]
    });
    
    var camera_circle = new Kinetic.Circle({
        x: start_x,
        y: start_y,
        radius: max_camera+5,
        stroke: 'white',
        strokeWidth: 5,
        lineJoin: "round",
        dashArray: [5, 5]
    });
    
    var inner_circle = new Kinetic.Circle({
        x: start_x,
        y: start_y,
        radius: (start_x+start_y)/8,
        stroke: 'green',
        strokeWidth: 1,
        lineJoin: "round",
        dashArray: [5, 5]
    });
    
    //shapesLayer.add(text_x);
    //shapesLayer.add(text_y);
    shapesLayer.add(camera_circle);
    shapesLayer.add(vert_line);
    shapesLayer.add(horz_line);
    //shapesLayer.add(outer_circle);
    shapesLayer.add(inner_circle);
    
    function camera_bound(pos) {
        var x = pos.x;
        var y = pos.y;
        var relx = (x - start_x)/max_camera;
        var rely = (y - start_y)/max_camera;
        var dist = Math.sqrt(Math.pow(relx, 2) + Math.pow(rely, 2));
        if (dist > 1) {
            relx /= dist;
            rely /= dist;
            return {
                x: relx*max_camera+start_x,
                y: rely*max_camera+start_y
            }
        }
        return pos;
    }
    
    function movement_bound(pos) {
        var relx = (pos.x - start_x)/max_turning;
        var rely = (pos.y - start_y)/max_driving;
        if (rover.moving == NOT_MOVING) {
            // check which way the knob is being dragged to choose what to do
            if (Math.abs(relx) > Math.abs(rely)) {
                if (Math.abs(relx) > min_movement) {
                    // turning motion
                    vert_line.setStroke('gray');
                    horz_line.setStroke('red');
                    knob.setFill('red');
                    rover.moving = MOVING_TURN;
                }
                else {
                    // not enough movement
                    return pos;
                }
            }
            else if (Math.abs(rely) > min_movement) {
                // driving motion
                horz_line.setStroke('gray');
                vert_line.setStroke('red');
                knob.setFill('blue');
                rover.moving = MOVING_DRIVE;
            }
            else {
                // not enough movement
                return pos;
            }
        }
        if (rover.moving == MOVING_DRIVE) {
            // constraint movement to y axis
            if (rely > 1.0)
                rely = 1.0;
            else if (rely < -1.0)
                rely = -1.0;
            if (Math.abs(rely) < min_movement) {
                reset_stage();
            }
            relx = 0.0;
        }
        else if (rover.moving == MOVING_TURN) {
            // constraint movement to x axis
            if (relx > 1.0)
                relx = 1.0;
            else if (relx < -1.0)
                relx = -1.0;
            if (Math.abs(relx) < min_movement) {
                reset_stage();
            }
            else if (Math.abs(relx) < min_turning) {
                knob.setFill('red');
            }
            else {
                knob.setFill('blue');
            }
            rely = 0.0;
        }
        return {
            y: Math.round(start_y + rely * max_driving),
            x: Math.round(start_x + relx * max_turning)
        };
    }
    
    var knob = new Kinetic.Circle({
        x: start_x,
        y: start_y,
        radius: (start_x+start_y)/8,
        fill: 'green',
        stroke: 'black',
        strokeWidth: 3,
        draggable: true,
        dragBoundFunc: movement_bound
    });
    
    function update_movement() {
        if (rover.camera) {
            rover.setCameraH(Math.round((start_x-knob.getX())/max_camera*90)+90);
            rover.setCameraV(Math.round((knob.getY()-start_y)/max_camera*90)+90);
        }
        else {
            if (rover.moving == MOVING_DRIVE)
                rover.setSpeed(Math.round((start_y-knob.getY())/max_driving*10));
            if (rover.moving == MOVING_TURN) {
                var speed = Math.round((knob.getX()-start_x)/max_turning*10);
                if (Math.abs(speed) < min_turning*10) speed = 1;
                rover.setSpeed(speed);
            }
        }
        stage.draw();
    };
    
    function reset_stage() {
        if (rover.camera) {
        }
        else {
            knob.setX(start_x);
            knob.setY(start_y);
            vert_line.setStroke('green');
            horz_line.setStroke('green');
            knob.setFill('green');
            rover.stop();
            update_movement();
        }
    };
        
    knob.on('dragmove', function() {
        update_movement();
    });
    knob.on('mouseup', function() {
        reset_stage();
    });
    document.getElementById('control_pad').addEventListener('mousedown',
        function(ev) {
            ev.preventDefault();
        }, false);
    document.addEventListener('mouseup', reset_stage, false);
    document.addEventListener('touchend', reset_stage, false);
    shapesLayer.add(knob);
    stage.add(shapesLayer);
    
    rover.show_camera_controls = function () {
        console.log('show_camera_controls start');
        camera_circle.setStroke('green');
        horz_line.setStroke('orange');
        vert_line.setStroke('orange');
        knob.setDragBoundFunc(camera_bound);
        stage.draw();
        console.log('show_camera_controls end');
    };
    rover.show_movement_controls = function () {
        console.log('show_movement_controls start');
        camera_circle.setStroke('white');
        horz_line.setStroke('green');
        vert_line.setStroke('green');
        knob.setDragBoundFunc(movement_bound);
        reset_stage();
        console.log('show_movement_controls end');
    };
    rover.set_camera_pos_h = function (horz) {
        x = start_x + (90-horz)*max_camera/90;
        console.log('x->'+x);
        knob.setX(x);
        rover.camh = horz;
        stage.draw();
    };
    rover.set_camera_pos_v = function (vert) {
        y = start_y + (vert-90)*max_camera/90;
        console.log('y->'+y);
        knob.setY(y);
        rover.camv = vert;
        stage.draw();
    };
}

function hide_pad() {
    document.getElementById('control_area').style.visibility = 'hidden';
}
function show_pad() {
    document.getElementById('control_area').style.visibility = 'visible';
}

function handler_text(params) {
    var code = params[0];
    var text = params[1];
    var msgclass;
    switch (code) {
        case 'connected':
            msgclass = 'good';
            var video = document.getElementById('video1');
            video.src = video.src;
            break;
        case 'connection lost':
        case 'protocol error':
            msgclass = 'bad';
            break;
        case 'connection failed':
            msgclass = 'note';
            break;
        case 'chosen':
            msgclass = 'info';
            show_big_message(text);
            show_pad();
            break;
        case 'not chosen':
            msgclass = 'info';
            show_big_message(text);
            hide_pad();
            break;
    }
    add_log(text, msgclass);
}

function handler_mars(params) {
    var code = params[0];
    var value = params[1];
    switch (code) {
		case 'R': // spectrum r
            var spec_data = document.getElementById('sensor_spec_data');
            var data = spec_data.innerText.split(',');
            data[0] = value;
            spec_data.innerText = data[0]+','+data[1]+','+data[2]+','+data[3];
            break;
		case 'G': // spectrum g
            var spec_data = document.getElementById('sensor_spec_data');
            var data = spec_data.innerText.split(',');
            data[1] = value;
            spec_data.innerText = data[0]+','+data[1]+','+data[2]+','+data[3];
            break;
		case 'B': // spectrum b
            var spec_data = document.getElementById('sensor_spec_data');
            var data = spec_data.innerText.split(',');
            data[2] = value;
            spec_data.innerText = data[0]+','+data[1]+','+data[2]+','+data[3];
            break;
		case 'IR': // spectrum ir
            var spec_data = document.getElementById('sensor_spec_data');
            var data = spec_data.innerText.split(',');
            data[3] = value;
            spec_data.innerText = data[0]+','+data[1]+','+data[2]+','+data[3];
            break;
        case 'AX': // accelerometer x
            var acc_data = document.getElementById('sensor_acc_data');
            var data = acc_data.innerText.split(',');
            data[0] = value;
            acc_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
        case 'AY': // accelerometer y
            var acc_data = document.getElementById('sensor_acc_data');
            var data = acc_data.innerText.split(',');
            data[1] = value;
            acc_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
        case 'AZ': // accelerometer z
            var acc_data = document.getElementById('sensor_acc_data');
            var data = acc_data.innerText.split(',');
            data[2] = value;
            acc_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
        case 'MX': // magnetic x
            var mag_data = document.getElementById('sensor_mag_data');
            var data = mag_data.innerText.split(',');
            data[0] = value;
            mag_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
        case 'MY': // magnetic y
            var mag_data = document.getElementById('sensor_mag_data');
            var data = mag_data.innerText.split(',');
            data[1] = value;
            mag_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
        case 'MZ': // magnetic z
            var mag_data = document.getElementById('sensor_mag_data');
            var data = mag_data.innerText.split(',');
            data[2] = value;
            mag_data.innerText = data[0]+','+data[1]+','+data[2];
            break;
		case 'HU': // humidity
            var hum_data = document.getElementById('sensor_hum_data');
            hum_data.innerText = value;
            break;
		case 'TE': // temperature
            var temp_data = document.getElementById('sensor_temp_data');
            temp_data.innerText = value;
            break;
		case 'AU': // solar panel
            var solar_data = document.getElementById('sensor_solar_data');
            solar_data.innerText = value;
            break;
        case 'H': // camera horizontal
            console.log('H:'+value);
            rover.set_camera_pos_h(value);
            break;
        case 'P': // camera vertical
            console.log('P:'+value);
            rover.set_camera_pos_v(value);
            break;
        default:
            console.log('Unknown message: "'+code+':'+value+'"');
            break;
    }
}

function add_log(text, msgclass) {
    function pad(num) {
        if (num < 10) return '0'+num;
        return ''+num;
    }
    var now = new Date();
    var h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
    var logtext = '['+pad(h)+':'+pad(m)+':'+pad(s)+'] '+text;
    var loglist = document.getElementById('loglist');
    var listnode = document.createElement('li');
    listnode.innerText = logtext;
    listnode.className = msgclass;
    loglist.appendChild(listnode);
    loglist.parentNode.scrollByLines(1);
}

function show_big_message(text) {
    var bigmsgbox = document.getElementById('bigmsg');
    bigmsgbox.innerText = text;
    bigmsg.style.visibility = 'visible'
    bigmsg.style.opacity = 1;
    setTimeout(function (){
        bigmsgbox.style.opacity = 0;
    }, 3000);
    setTimeout(function (){
        bigmsgbox.style.visibility = 'hidden';
        bigmsgbox.innerText = '';
    }, 4000);
}

function setLanguage(langid) {
    interface_language = langid;
    mars.send('set:language:'+langid);
    if (langid == 'fi') {
        document.getElementById('cambutton').innerText = "Kameran ohjaus";
        document.getElementById('camreset').innerText = "Kamera eskelle";
        document.getElementById('sensor_acc_name').innerText = "Kiihtyvyys";
        document.getElementById('sensor_mag_name').innerText = "Kompassi";
    }
    else {
        document.getElementById('cambutton').innerText = "Control camera";
        document.getElementById('camreset').innerText = "Center camera";
        document.getElementById('sensor_acc_name').innerText = "Acceleration";
        document.getElementById('sensor_mag_name').innerText = "Compass";
    }
}

function switch_control() {
    // switch control between camera and movement
    if (rover.camera) {
        // switch back to movement
        document.getElementById('control_pad').style.background = 'white';
        document.getElementById('cambutton').style.background = '';
        rover.detachCamera();
        rover.show_movement_controls();
    }
    else {
        // switch to camera control
        document.getElementById('control_pad').style.background = 'orange';
        document.getElementById('cambutton').style.background = 'blue';
        rover.set_camera_pos_h(rover.camh);
        rover.set_camera_pos_v(rover.camv);
        rover.askCameraPosition();
        rover.attachCamera();
        rover.show_camera_controls();
    }
}

function reset_camera() {
    // reset camera position
    var move_cam = true;
    if (!rover.camera) {
        move_cam = false;
        rover.attachCamera(false);
        setTimeout(function () {
            if (!rover.camera) rover.detachCamera();
        }, 1000);
    }
    rover.setCameraH(90);
    rover.setCameraV(90);
    if (move_cam) {
        rover.set_camera_pos_h(90);
        rover.set_camera_pos_v(90);
    }
}

function make_connection() {
    function onopen(ev) {
        if (interface_language == 'fi') {
            add_log('Yhteys muodostettu.', 'good');
        }
        else {
            add_log('Connection established.', 'good');
        }
        setLanguage(interface_language); // set language
        mars.send('control'); // request control
    }
    function onclose(ev) {
        if (interface_language == 'fi') {
            add_log('Yhteys katkaistu.', 'bad');
        }
        else {
            add_log('Connection closed.', 'bad');
        }
    }
    function onerror(ev) {
        if (interface_language == 'fi') {
            add_log('Yhteydessä tapahtui virhe.', 'bad');
        }
        else {
            add_log('Error happened in connection.', 'bad');
        }
        mars.close();
    }
    mars = connect_to_mars('ws://'+document.location.hostname+':'+
        document.location.port+'/mars',
        onopen, onclose, onerror);
    mars.register_handler('TEXT', handler_text);
    mars.register_handler('mars', handler_mars);
}

function initialize(ev) {
    // Initialization routines
    create_pad(); // Create the directional control pad
    hide_pad(); // Hide the pad by default
    make_connection(); // Make connection with the server
}

document.addEventListener('DOMContentLoaded', initialize, false);

